/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef CRC_DRV_H
#define CRC_DRV_H

/*!
 * @file crc_drv.h
 * @brief This file declares crc driver interfaces
 */

/*!
 * @addtogroup crc_drv
 * @{
 */

/*******Includes***************************************************************/
#include <stdint.h>
#include <stdbool.h>
#include "dma_drv.h"

/*******Definitions************************************************************/

/*!
 * @brief CRC protocol type
 */
typedef enum {
    CRC16_PROTOCOL      = 0U,        /*!< CRC16 */
    CRC32_PROTOCOL      = 1U         /*!< CRC32 */
} crc_protocol_t;

/*!
 * @brief type of transpose for read and write data
 */
typedef enum {
    CRC_TRANSPOSE_NONE           = 0U,   /*!< CRC no transposition */
    CRC_TRANSPOSE_BITS_ONLY      = 1U,   /*!< CRC transposed bits in bytes */
    CRC_TRANSPOSE_BITS_AND_BYTES = 2U,   /*!< CRC transposed bits in bytes and bytes */
    CRC_TRANSPOSE_BYTES_ONLY     = 3U    /*!< CRC transposed bytes */
} crc_transpose_t;

/*!
 * @brief CRC driver configuration structure
 */
typedef struct {
    uint32_t seed;                  /*!< Checksum initial value. */
    uint32_t polynomial;            /*!< CRC polynomial value */
    crc_protocol_t crcProtocol;     /*!< CRC protocol, CRC16 or CRC32 */
    crc_transpose_t writeTranspose; /*!< Type of transpose when writing CRC data. */
    crc_transpose_t readTranspose;  /*!< Type of transpose when reading CRC result. */
    bool checksumXOR;               /*!< True if the result shall be complement of the actual checksum */
} crc_config_t;

/*!
 * @brief CRC calculate use DMA driver configuration structure
 */
typedef struct {
    uint8_t channel;            /*!< Channel Id */
    uint32_t srcAddress;        /*!< Memory address pointing to the source data */
    uint32_t dataLength;        /*!< Transfer size: 0~4095, set it directly acoording to the source data type */
    dma_transfer_width_t width; /*!< Transfer width: 8/16/32bits
                                     If the source data type is uint8_t,  set DMA_TRANSFER_WIDTH_8BIT
                                     If the source data type is uint16_t, set DMA_TRANSFER_WIDTH_16BIT
                                     If the source data type is uint16_t, set DMA_TRANSFER_WIDTH_32BIT */
    dma_callback_t callback;    /*!< DMA callback function */
    void* callbackParam;        /*!< DMA callback function parameters */
} crc_dma_config_t;

/*******APIs*******************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief Initializes the CRC module based on user configuration
 *
 * @param[in] instance:  The CRC instance number
 * @param[in] crcConfig: Pointer to structure of initialization
 * @return    None
 */
void CRC_Init(uint32_t instance,
              const crc_config_t* crcConfig);

/*!
 * @brief DeInitializes the CRC module and reset CRC module
 *
 * @param[in] instance: The CRC instance number
 * @return None
 */
void CRC_Deinit(uint32_t instance);

/*!
 * @brief Start CRC32 calculate for a block of bytes and return the result
 *        when the data is transfered by CPU
 *
 * @param[in] instance:   The CRC instance number
 * @param[in] dataBuff:   Data for CRC32 calculation, data pointer is 8bit width
 * @param[in] dataLength: Length of bytes to be calculated
 * @param[in] seed:       Initial value of the CRC calculation
 * @param[in] isNewSeed:  True if the seed is the initial value for current calculation
 * @return Result of CRC calculation
 */
uint32_t CRC_CalcCrc32InByte(uint32_t instance,
                             const uint8_t* dataBuff,
                             uint32_t dataLength,
                             uint32_t seed,
                             bool isNewSeed);

/*!
 * @brief Start CRC32 calculate for a block of Halfwords and return the result
 *        when the data is transfered by CPU
 *
 * @param[in] instance:   The CRC instance number
 * @param[in] dataBuff:   Data for CRC32 calculation, data pointer is 16bit width
 * @param[in] dataLength: Length of Halfwords to be calculated
 * @param[in] seed:       Initial value of the CRC calculation
 * @param[in] isNewSeed:  True if the seed is the initial value for current calculation
 * @return Result of CRC calculation
 */
uint32_t CRC_CalcCrc32InHalfword(uint32_t instance,
                                 const uint16_t* dataBuff,
                                 uint32_t dataLength,
                                 uint32_t seed,
                                 bool isNewSeed);

/*!
 * @brief Start CRC32 calculate for a block of Words and return the result
 *        when the data is transfered by CPU
 *
 * @param[in] instance:   The CRC instance number
 * @param[in] dataBuff:   Data for CRC32 calculation, data pointer is 32bit width
 * @param[in] dataLength: Length of words to be calculated
 * @param[in] seed:       Initial value of the CRC calculation
 * @param[in] isNewSeed:  True if the seed is the initial value for current calculation
 * @return Result of CRC calculation
 */
uint32_t CRC_CalcCrc32InWord(uint32_t instance,
                             const uint32_t* dataBuff,
                             uint32_t dataLength,
                             uint32_t seed,
                             bool isNewSeed);

/*!
 * @brief Start CRC16 calculate for a block of bytes and return the result
 *        when the data is transfered by CPU
 *
 * @param[in] instance:   The CRC instance number
 * @param[in] dataBuff:   Data for CRC16 calculation, data pointer is 8bit width
 * @param[in] dataLength: Length of data to be calculated
 * @param[in] seed:       Initial value of the CRC calculation
 * @param[in] isNewSeed:  True if the seed is the initial value for current calculation
 * @return Result of CRC calculation
 */
uint16_t CRC_CalcCrc16InByte(uint32_t instance,
                             const uint8_t* dataBuff,
                             uint32_t dataLength,
                             uint16_t seed,
                             bool isNewSeed);

/*!
 * @brief Start CRC16 calculate for a block of Halfwords and return the result
 *        when the data is transfered by CPU
 *
 * @param[in] instance:   The CRC instance number
 * @param[in] dataBuff:   Data for CRC16 calculation, data pointer is 16bit width
 * @param[in] dataLength: Length of Halfwords to be calculated
 * @param[in] seed:       Initial value of the CRC calculation
 * @param[in] isNewSeed:  True if the seed is the initial value for current calculation
 * @return Result of CRC calculation
 */
uint16_t CRC_CalcCrc16InHalfword(uint32_t instance,
                                 const uint16_t* dataBuff,
                                 uint32_t dataLength,
                                 uint16_t seed,
                                 bool isNewSeed);

/*!
 * @brief Calculate crc, the data is transfered by DMA
 *
 * @param[in] instance: The CRC instance number
 * @param[in] dmaConfig: dma configuration for crc calculation
 * @param[in] seed:       Initial value of the CRC calculation
 * @param[in] isNewSeed:  True if the seed is the initial value for current calculation
 * @return None
 */
void CRC_CalcCrcByDMA(uint32_t instance,
                      const crc_dma_config_t* dmaConfig,
                      uint32_t seed,
                      bool isNewSeed);

/*!
 * @brief Returns the current result of the CRC calculation
 *        when the data is transfered by DMA
 *
 * @param[in] instance: The CRC instance number
 * @return Result of CRC calculation
 */
uint32_t CRC_GetCrcResult(uint32_t instance);

/*!
 * @brief Get default configures(CRC16_CCITT_FALSE) the CRC module for configuration structure
 *
 * @param[out] crcConfig: Pointer to structure of initialization
 * @return None
 */
void CRC_GetDefaultConfig(crc_config_t* crcConfig);


#if defined(__cplusplus)
}
#endif

/*! @} */

#endif /* CRC_DRV_H */

/*******EOF********************************************************************/
